package org.nicocube.airain.domain.server.dao;

import java.util.LinkedList;
import java.util.List;

import javax.jdo.Query;

public class DomainQuery<T> {
	private class Param<O> {
		private final String column;
		private final Class<O> oClass;
		private final O o;

		public Param(String column, Class<O> oClass, O o) {
			this.column = column;
			this.oClass = oClass;
			this.o = o;
		}

	}

	private final Class<T> clazz;
	private final Query query;
	private final List<Param<?>> args;

	DomainQuery(Class<T> clazz,Query query) {
		this.clazz = clazz;
		this.query = query;
		args = new LinkedList<Param<?>>();
	}

	public <X> DomainQuery<X> withResult(Class<X> type,String arg0) {
		query.setResult(arg0);
		return new DomainQuery<X>(type,query);
	}

	public T execute() {
		return clazz.cast(query.executeWithArray(prepareCriterias()));
	}

	@SuppressWarnings("unchecked")
	public List<T> executeList() {
		return (List<T>) query.executeWithArray(prepareCriterias());
	}


	private Object[] prepareCriterias() {
		Object[] res = new Object[args.size()];

		StringBuilder filter = new StringBuilder();
		StringBuilder paramDeclaration = new StringBuilder();

		int i = 0;
		for (Param<?> arg : args) {
			String n = arg.column+"Param"+i;

			if (i!=0) filter.append(" && ");
			filter.append(arg.column).append(" == ").append(n);

			if (i!=0) paramDeclaration.append(", ");
			paramDeclaration.append(arg.oClass.getName()).append(" ").append(n);

			res[i]=arg.o;
			i++;
		}

		if (i != 0) {
			query.setFilter(filter.toString());
			query.declareParameters(paramDeclaration.toString());
		}
	
		return res;
	}

	public <O> DomainQuery<T> addCriteria(String column, Class<O> oClass, O o) {
		args.add(new Param<O>(column,oClass,o));
		return this;
	}

	public DomainQuery<T> setOrdering(String string) {
		query.setOrdering("creationDate desc");
		return this;
	}

}
